/*
 * @Author       : Bing Chen chenbing@iocharger.com
 * @Date         : 2025-01-21 16:09:28
 * @LastEditors  : Bing Chen chenbing@iocharger.com
 * @LastEditTime : 2025-03-15 13:06:18
 * @FilePath     : \openchaoji-corelib\x86\secc\hal_compile_secc_x86.c
 * @Description  :
 *
 * Copyright (c) 2025 OpenChaoJi
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the icense for the specific language governing permissions and
 * limitations under the License.
 *
 */
#include "../include/OpenChaoJi_secc.h"

#include "../app_hal_x86.h"
#include "secc_x86.h"

struct secc_hal_selfcheck
{
    bool start;
    uint32_t start_ticks;

    uint32_t time_adhesion;       //粘连检测状态
    uint32_t time_short;          //短路检测状态
    uint32_t time_imd;            //绝缘检测状态
};

struct secc_hal_power_component
{
    // 配置部分
    uint32_t voltage_max;         //最大电压(0.1V)
    uint32_t voltage_min;         //最小电压(0.1V)
    uint32_t current_max;         //最大电流(0.1A)
    uint32_t current_min;         //最小电流(0.1A)
    uint32_t power_max;           //最大功率(0.01kW)
    uint32_t power_min;           //最小功率(0.01kW)
    uint32_t voltage_raise_rate;  //升压速率(0.1V/ms)
    uint32_t voltage_drop_rate;   //降压速率(0.1V/ms)
    uint32_t current_raise_rate;  //升流速率(0.1A/ms)
    uint32_t current_drop_rate;   //降流速率(0.1A/ms)

    // 运行部分
    bool start;                   //是否启动
    uint32_t start_ticks;         //启停时间戳
    uint32_t start_voltage;       //启停时刻的电压(0.1V)
    uint32_t start_current;       //启停时刻的电流(0.1A)
    uint32_t target_voltage;      //目标电压(0.1V)
    uint32_t target_current;      //目标电流(0.1A)

    // 计算实时状态
    uint32_t voltage;             //电压(0.1V)
    uint32_t current;             //电流(0.1A)
    uint32_t power;               //功率(0.01kW)
};

struct secc_hal_info
{
    int idx;

    int socket_secc;
    struct sockaddr_in dest_addr_evcc;
    fifo_queue recv_queue;

    // 导引控制相关继电器, 需要同步给evcc
    struct can_data_pilot_sync pilot_sync_status;
    uint32_t sync_send_ticks;

    struct hal_x86_relay relay_pe_lost; // PE断开模拟
    struct hal_x86_relay relay_s0;
    struct hal_x86_relay relay_s1;

    // 非导引同步相关继电器
    struct hal_x86_relay relay_dc;
    struct hal_x86_relay relay_ac;
    struct hal_x86_relay relay_aux;
    struct hal_x86_relay relay_lock;
    struct hal_x86_relay relay_emergency;

    // 自检
    struct secc_hal_selfcheck self_check;

    // 电源模块
    struct secc_hal_power_component power_component;
};

static struct secc_hal_info s_hal_info_secc[HAL_SIMU_CONNECTOR_NUM];


static void secc_hal_selfcheck_reset(struct secc_hal_selfcheck *self_check)
{
    self_check->start = false;
    self_check->start_ticks = 0;
}

static void secc_hal_power_component_reset(struct secc_hal_power_component *power_component)
{
    power_component->start = false;
    power_component->start_ticks = 0;
    power_component->start_voltage = 0;
    power_component->start_current = 0;
    power_component->target_voltage = 0;
    power_component->target_current = 0;
    power_component->voltage = 0;
    power_component->current = 0;
    power_component->power = 0;
}

void secc_hal_one_reset(int idx)
{
    secc_hal_selfcheck_reset(&s_hal_info_secc[idx].self_check);
    secc_hal_power_component_reset(&s_hal_info_secc[idx].power_component);

    hal_x86_relay_set(idx, &s_hal_info_secc[idx].relay_pe_lost, 0);
    hal_x86_relay_set(idx, &s_hal_info_secc[idx].relay_s0, 1);
    hal_x86_relay_set(idx, &s_hal_info_secc[idx].relay_s1, 0);
    hal_x86_relay_set(idx, &s_hal_info_secc[idx].relay_dc, 0);
    hal_x86_relay_set(idx, &s_hal_info_secc[idx].relay_ac, 0);
    hal_x86_relay_set(idx, &s_hal_info_secc[idx].relay_aux, 0);
    hal_x86_relay_set(idx, &s_hal_info_secc[idx].relay_lock, 0);
    hal_x86_relay_set(idx, &s_hal_info_secc[idx].relay_emergency, 0);

}

void secc_hal_one_init(int idx)
{
    memset(&s_hal_info_secc[idx], 0x00, sizeof(struct secc_hal_info));

    s_hal_info_secc[idx].idx = idx;

    // 初始化SECC与EVCC通信的socket
    s_hal_info_secc[idx].socket_secc = hal_create_udp_socket(HAL_UDP_PORT_SECC_START + idx);
    hal_init_dest_socket_addr(HAL_UDP_ADDR_EVCC, HAL_UDP_PORT_EVCC_START + idx, &s_hal_info_secc[idx].dest_addr_evcc);
    fifo_init(&s_hal_info_secc[idx].recv_queue);

    // 初始化导引同步相关继电器
    if (idx == 0)
    {
        s_hal_info_secc[idx].pilot_sync_status.pilot_type = HA_SIMU_PILOT_A_A;
    }
    else if (idx == 1)
    {
        s_hal_info_secc[idx].pilot_sync_status.pilot_type = HA_SIMU_PILOT_B_B;
    }
    else if (idx == 2)
    {
        s_hal_info_secc[idx].pilot_sync_status.pilot_type = HA_SIMU_PILOT_B_A;
    }

    // PE断开模拟, 常开
    hal_x86_relay_init(&s_hal_info_secc[idx].relay_pe_lost, "pe_lost", 10, 10, 0);
    s_hal_info_secc[idx].pilot_sync_status.secc_pe_lost = 0;

    // S0选配, 常闭
    hal_x86_relay_init(&s_hal_info_secc[idx].relay_s0, "s0", 10, 10, 1);
    s_hal_info_secc[idx].pilot_sync_status.secc_S0 = 1;

    // S1初始状态断开
    hal_x86_relay_init(&s_hal_info_secc[idx].relay_s1, "s1", 100, 50, 0);
    s_hal_info_secc[idx].pilot_sync_status.secc_S1 = 0;

    // 其他开关默认都是断开
    hal_x86_relay_init(&s_hal_info_secc[idx].relay_dc, "dc", 100, 50, 0);
    s_hal_info_secc[idx].pilot_sync_status.secc_dc = 0;

    hal_x86_relay_init(&s_hal_info_secc[idx].relay_ac, "ac", 100, 50, 0);
    s_hal_info_secc[idx].pilot_sync_status.secc_ac = 0;

    hal_x86_relay_init(&s_hal_info_secc[idx].relay_aux, "aux", 100, 50, 0);
    s_hal_info_secc[idx].pilot_sync_status.secc_aux = 0;

    hal_x86_relay_init(&s_hal_info_secc[idx].relay_lock, "lock", 100, 50, 0);
    s_hal_info_secc[idx].pilot_sync_status.secc_lock = 0;

    hal_x86_relay_init(&s_hal_info_secc[idx].relay_emergency, "emergency", 100, 50, 0);
    s_hal_info_secc[idx].pilot_sync_status.secc_emergency = 0;

    // 初始化自检相关
    s_hal_info_secc[idx].self_check.time_adhesion = 1000;
    s_hal_info_secc[idx].self_check.time_short = 2000;
    s_hal_info_secc[idx].self_check.time_imd = 3000;

    secc_hal_selfcheck_reset(& s_hal_info_secc[idx].self_check);

    // 初始化模块相关(200-100V, 600kW超充, 300-1000V恒功率, 20个30kW模块)
    s_hal_info_secc[idx].power_component.voltage_max = 10000;
    s_hal_info_secc[idx].power_component.voltage_min = 2000;
    s_hal_info_secc[idx].power_component.current_max = 20000;
    s_hal_info_secc[idx].power_component.current_min = 0;
    s_hal_info_secc[idx].power_component.power_max = 60000;
    s_hal_info_secc[idx].power_component.power_min = 0;
    s_hal_info_secc[idx].power_component.voltage_raise_rate = 2; // 200V/s = 0.2V/ms
    s_hal_info_secc[idx].power_component.voltage_drop_rate = 3; // 300V/s = 0.3V/ms
    s_hal_info_secc[idx].power_component.current_raise_rate = 2; // 200A/s = 0.2A/ms
    s_hal_info_secc[idx].power_component.current_drop_rate = 3; // 300A/s = 0.3A/ms

    secc_hal_power_component_reset(&s_hal_info_secc[idx].power_component);

    return;
}

void secc_hal_one_term(int idx)
{
    close(s_hal_info_secc[idx].socket_secc);
}

OpenChaoJi_hal_handle secc_hal_one_handle(int idx)
{
    if ((idx >= 0) && (idx < HAL_SIMU_CONNECTOR_NUM))
    {
        return (OpenChaoJi_hal_handle)(&s_hal_info_secc[idx]);
    }

    return NULL;
}

static struct secc_hal_info * secc_hal_handle2Info(OpenChaoJi_hal_handle hal_handle)
{
    for (int idx = 0; idx < HAL_SIMU_CONNECTOR_NUM; idx++)
    {
        if (secc_hal_one_handle(idx) == hal_handle)
        {
            return &s_hal_info_secc[idx];
        }
    }

    return NULL;
}

// 更新继电器状态字节, 如果变化则发送给evcc
static bool secc_hal_x86_relay_sync(struct secc_hal_info * info)
{
    uint8_t pe_lost = hal_x86_relay_get(info->idx, &info->relay_pe_lost);
    uint8_t s0 = hal_x86_relay_get(info->idx, &info->relay_s0);
    uint8_t s1 = hal_x86_relay_get(info->idx, &info->relay_s1);
    uint8_t dc = hal_x86_relay_get(info->idx, &info->relay_dc);
    uint8_t ac = hal_x86_relay_get(info->idx, &info->relay_ac);
    uint8_t aux = hal_x86_relay_get(info->idx, &info->relay_aux);
    uint8_t lock = hal_x86_relay_get(info->idx, &info->relay_lock);
    uint8_t emergency = hal_x86_relay_get(info->idx, &info->relay_emergency);

    bool changed = false;
    if (info->pilot_sync_status.secc_pe_lost != pe_lost)
    {
        LOG_PILOT_HAL("[%d]pe_lost: %d -> %d", info->idx, info->pilot_sync_status.secc_pe_lost, pe_lost);
        info->pilot_sync_status.secc_pe_lost = pe_lost;
        changed = true;
    }
    if (info->pilot_sync_status.secc_S0 != s0)
    {
        LOG_PILOT_HAL("[%d]secc_S0: %d -> %d", info->idx, info->pilot_sync_status.secc_S0, s0);
        info->pilot_sync_status.secc_S0 = s0;
        changed = true;
    }
    if (info->pilot_sync_status.secc_S1 != s1)
    {
        LOG_PILOT_HAL("[%d]secc_S1: %d -> %d", info->idx, info->pilot_sync_status.secc_S1, s1);
        info->pilot_sync_status.secc_S1 = s1;
        changed = true;
    }
    if (info->pilot_sync_status.secc_dc != dc)
    {
        LOG_PILOT_HAL("[%d]secc_dc: %d -> %d", info->idx, info->pilot_sync_status.secc_dc, dc);
        info->pilot_sync_status.secc_dc = dc;
        changed = true;
    }
    if (info->pilot_sync_status.secc_ac != ac)
    {
        LOG_PILOT_HAL("[%d]secc_ac: %d -> %d", info->idx, info->pilot_sync_status.secc_ac, ac);
        info->pilot_sync_status.secc_ac = ac;
        changed = true;
    }
    if (info->pilot_sync_status.secc_aux != aux)
    {
        LOG_PILOT_HAL("[%d]secc_aux: %d -> %d", info->idx, info->pilot_sync_status.secc_aux, aux);
        info->pilot_sync_status.secc_aux = aux;
        changed = true;
    }
    if (info->pilot_sync_status.secc_lock != lock)
    {
        LOG_PILOT_HAL("[%d]secc_lock: %d -> %d", info->idx, info->pilot_sync_status.secc_lock, lock);
        info->pilot_sync_status.secc_lock = lock;
        changed = true;
    }
    if (info->pilot_sync_status.secc_emergency != emergency)
    {
        LOG_PILOT_HAL("[%d]secc_emergency: %d -> %d", info->idx, info->pilot_sync_status.secc_emergency, emergency);
        info->pilot_sync_status.secc_emergency = emergency;
        changed = true;
    }

    return changed;
}

static bool secc_hal_power_component_service(struct secc_hal_info * info)
{
    uint32_t voltage = 0;
    uint32_t current = 0;

    uint32_t ticks = OpenChaoJi_os_get_ticks();
    uint32_t diff_ticks = ticks - info->power_component.start_ticks;
    uint32_t max_ms = 0;

    bool changed = false;

    // 需要调整电压
    if (info->power_component.voltage != info->power_component.target_voltage)
    {
        // 目标电压 >= 起始电压, 升压过程
        if (info->power_component.target_voltage >= info->power_component.start_voltage)
        {
            // 最大升压时间
            max_ms = (info->power_component.target_voltage - info->power_component.start_voltage) / info->power_component.voltage_raise_rate;

            if (diff_ticks >= max_ms)
            {
                // 到了最大升压时间(目标电压)后不再升压
                voltage = info->power_component.target_voltage;
            }
            else
            {
                // 按照当前时间计算升压后的电压值
                voltage = info->power_component.start_voltage + diff_ticks * info->power_component.voltage_raise_rate;
            }
        }
        else
        {
            // 目标电压 < 起始电压, 降压过程

            // 最大降压时间
            max_ms = (info->power_component.start_voltage - info->power_component.target_voltage) / info->power_component.voltage_drop_rate;

            if (diff_ticks >= max_ms)
            {
                // 到了最大降压时间(目标电压)后不再降压
                voltage = info->power_component.target_voltage;
            }
            else
            {
                // 按照当前时间计算降压后的电压值
                voltage = info->power_component.start_voltage - diff_ticks * info->power_component.voltage_drop_rate;
            }
        }
    }
    else
    {
        voltage = info->power_component.voltage; // 不需要调整电压
    }

    // 以上是模块当前时间可以升压或降压的电压, 还需要再看电池是否投入, 否则以电池电压为准
    if (info->pilot_sync_status.evcc_dc && info->pilot_sync_status.secc_dc)
    {
        if (info->power_component.start)
        {
            voltage = info->pilot_sync_status.evcc_battery_voltage; // 电池电压
        }
    }

    if (voltage != info->power_component.voltage)
    {
        LOG_DATA_HAL("voltage: %d-%d", info->power_component.voltage, voltage);
        info->power_component.voltage = voltage;
        changed = true;
    }

    if (info->power_component.current != info->power_component.target_current)
    {
        // 目标电流 >= 起始电流, 升压过程
        if (info->power_component.target_current >= info->power_component.start_current)
        {
            // 最大升压时间
            max_ms = (info->power_component.target_current - info->power_component.start_current) / info->power_component.current_raise_rate;

            if (diff_ticks >= max_ms)
            {
                // 到了最大升压时间(目标电流)后不再升压
                current = info->power_component.target_current;
            }
            else
            {
                // 按照当前时间计算升压后的电流值
                current = info->power_component.start_current + diff_ticks * info->power_component.current_raise_rate;
            }
        }
        else
        {
            // 目标电流 < 起始电流, 降压过程

            // 最大降压时间
            max_ms = (info->power_component.start_current - info->power_component.target_current) / info->power_component.current_drop_rate;

            if (diff_ticks >= max_ms)
            {
                // 到了最大降压时间(目标电流)后不再降压
                current = info->power_component.target_current;
            }
            else
            {
                // 按照当前时间计算降压后的电流值
                current = info->power_component.start_current - diff_ticks * info->power_component.current_drop_rate;
            }
        }
    }
    else
    {
        current = info->power_component.current; // 不需要调整电流
    }

    // 以上是模块当前时间可以升压或降压的电流, 还需要再看电池是否投入, 否则以电流为0
    // 只要C1/C2 或者 C5/C6 断开, 则电流为0
    if (!info->pilot_sync_status.secc_dc || !info->pilot_sync_status.evcc_dc)
    {
        current = 0;
    }

    // 再需要判断当前设置电流是否超过总功率限制
    uint32_t power = (voltage * current / 1000); // 0.1V * 0.1A = 0.01W -> 0.01kW
    if (power > info->power_component.power_max)
    {
        power = info->power_component.power_max;

        current = (power * 1000 / voltage); // 0.01kW * 1000 = 10W -> 10A
    }

    if (info->power_component.current != current)
    {
        info->power_component.current = current;
        changed = true;
    }

    if (info->power_component.power != power)
    {
        info->power_component.power = power;
        changed = true;
    }

    return changed;
}

void secc_hal_one_service(int idx)
{
    if (idx >= 0 && idx < HAL_SIMU_CONNECTOR_NUM)
    {
        // 先刷新各个继电器状态(可能的命令行直接强制修改)
        hal_x86_relay_service(idx, &s_hal_info_secc[idx].relay_pe_lost);
        hal_x86_relay_service(idx, &s_hal_info_secc[idx].relay_s0);
        hal_x86_relay_service(idx, &s_hal_info_secc[idx].relay_s1);

        hal_x86_relay_service(idx, &s_hal_info_secc[idx].relay_dc);
        hal_x86_relay_service(idx, &s_hal_info_secc[idx].relay_ac);
        hal_x86_relay_service(idx, &s_hal_info_secc[idx].relay_aux);
        hal_x86_relay_service(idx, &s_hal_info_secc[idx].relay_lock);
        hal_x86_relay_service(idx, &s_hal_info_secc[idx].relay_emergency);

        // 更新继电器状态字节, 如果变化则发送给evcc;
        bool relay_changed = secc_hal_x86_relay_sync(&s_hal_info_secc[idx]);

        secc_hal_power_component_service(&s_hal_info_secc[idx]);

        bool power_changed = false;
        if (s_hal_info_secc[idx].pilot_sync_status.secc_output_power != s_hal_info_secc[idx].power_component.power)
        {
            LOG_DATA_HAL("[%d]power %d->%d", idx, s_hal_info_secc[idx].pilot_sync_status.secc_output_power, s_hal_info_secc[idx].power_component.power);
            s_hal_info_secc[idx].pilot_sync_status.secc_output_power = s_hal_info_secc[idx].power_component.power;
            power_changed = true;
        }

        if (relay_changed || power_changed || (OpenChaoJi_os_get_ticks() > s_hal_info_secc[idx].sync_send_ticks + 1000))
        {
            struct can_pdu can_send_info;
            can_send_info.can_id.uint32_tWord = CAN_ID_PILOT_SYNC;
            can_send_info.can_dlc = 8;
            memcpy(can_send_info.data, &s_hal_info_secc[idx].pilot_sync_status, 8);

            if (relay_changed)
            {
                LOG_PILOT_HAL("[%d]pilot->evcc", idx);
                hal_log_pilot_sync(&s_hal_info_secc[idx].pilot_sync_status);
            }

            OpenChaoJi_secc_hal_information_send_can_voluation(secc_hal_one_handle(idx), &can_send_info);
            s_hal_info_secc[idx].sync_send_ticks = OpenChaoJi_os_get_ticks();
        }
    }
}


/**
 * 导引电路, IO驱动等
 * 洛阳嘉盛
*/

/**
SECC 相关接口
*/

/*******************************CAN通信接口*******************************/

/**
 * @brief  CAN接收
 * @param  OpenChaoJi_hal_handle: 句柄
 * @param  can_info_type: can消息结构体
 * @return 0:OK 接收成功 -1:ERR 接受失败
 */
void secc_hal_can_data_pilot_sync_func_(OpenChaoJi_hal_handle handle, struct can_pdu * can_recv_info)
{
    struct secc_hal_info * info = secc_hal_handle2Info(handle);
    if (info == NULL)
    {
        LOG_ALERT("Invalid hal_handle %08X", handle);
        return;
    }

    struct can_data_pilot_sync sync;
    memcpy(&sync, can_recv_info->data, 8);

    bool changed = false;
    // secc只更新evcc的开关变化状态, 自身的开关状态从relay获取
    if (info->pilot_sync_status.evcc_plug != sync.evcc_plug)
    {
        LOG_PILOT_HAL("evcc_plug: %d -> %d", info->pilot_sync_status.evcc_plug, sync.evcc_plug);
        info->pilot_sync_status.evcc_plug = sync.evcc_plug;
        changed = true;
    }
    if (info->pilot_sync_status.evcc_pe_lost != sync.evcc_pe_lost)
    {
        LOG_PILOT_HAL("evcc_pe_lost: %d -> %d", info->pilot_sync_status.evcc_pe_lost, sync.evcc_pe_lost);
        info->pilot_sync_status.evcc_pe_lost = sync.evcc_pe_lost;
        changed = true;
    }
    if (info->pilot_sync_status.evcc_S != sync.evcc_S)
    {
        LOG_PILOT_HAL("evcc_S: %d -> %d", info->pilot_sync_status.evcc_S, sync.evcc_S);
        info->pilot_sync_status.evcc_S = sync.evcc_S;
        changed = true;
    }
    if (info->pilot_sync_status.evcc_S2 != sync.evcc_S2)
    {
        LOG_PILOT_HAL("evcc_S2: %d -> %d", info->pilot_sync_status.evcc_S2, sync.evcc_S2);
        info->pilot_sync_status.evcc_S2 = sync.evcc_S2;
        changed = true;
    }
    if (info->pilot_sync_status.evcc_S2p != sync.evcc_S2p)
    {
        LOG_PILOT_HAL("evcc_S2p: %d -> %d", info->pilot_sync_status.evcc_S2p, sync.evcc_S2p);
        info->pilot_sync_status.evcc_S2p = sync.evcc_S2p;
        changed = true;
    }
    if (info->pilot_sync_status.evcc_Sv != sync.evcc_Sv)
    {
        LOG_PILOT_HAL("evcc_Sv: %d -> %d", info->pilot_sync_status.evcc_Sv, sync.evcc_Sv);
        info->pilot_sync_status.evcc_Sv = sync.evcc_Sv;
        changed = true;
    }
    if (info->pilot_sync_status.evcc_dc != sync.evcc_dc)
    {
        LOG_PILOT_HAL("evcc_dc: %d -> %d", info->pilot_sync_status.evcc_dc, sync.evcc_dc);
        info->pilot_sync_status.evcc_dc = sync.evcc_dc;
        changed = true;
    }
    if (info->pilot_sync_status.evcc_lock != sync.evcc_lock)
    {
        LOG_PILOT_HAL("evcc_lock: %d -> %d", info->pilot_sync_status.evcc_lock, sync.evcc_lock);
        info->pilot_sync_status.evcc_lock = sync.evcc_lock;
        changed = true;
    }
    if (info->pilot_sync_status.evcc_emergency != sync.evcc_emergency)
    {
        LOG_PILOT_HAL("evcc_emergency: %d -> %d", info->pilot_sync_status.evcc_emergency, sync.evcc_emergency);
        info->pilot_sync_status.evcc_emergency = sync.evcc_emergency;
        changed = true;
    }
    if (info->pilot_sync_status.evcc_battery_voltage != sync.evcc_battery_voltage)
    {
        LOG_DATA_HAL("evcc_battery_voltage: %d -> %d", info->pilot_sync_status.evcc_battery_voltage, sync.evcc_battery_voltage);
        info->pilot_sync_status.evcc_battery_voltage = sync.evcc_battery_voltage;
        // changed = true;
    }
    if (changed)
    {
        LOG_PILOT_HAL("[%d]pilot<-evcc", info->idx);
        hal_log_pilot_sync(&sync);
    }

    return;
}

int OpenChaoJi_secc_hal_information_recv_can_voluation(OpenChaoJi_hal_handle handle, struct can_pdu * can_recv_info)
{
    HAL_DEBUG_LINE
    struct secc_hal_info * info = secc_hal_handle2Info(handle);
    if (info == NULL)
    {
        LOG_ALERT("Invalid hal_handle %08X", handle);
        return -1;
    }

    return hal_try_read_can_pdu(handle, info->socket_secc, &info->recv_queue, secc_hal_can_data_pilot_sync_func_, can_recv_info);
}

/**
 * @brief  CAN发送
 * @param  OpenChaoJi_hal_handle: 句柄
 * @param  can_info_type: can消息结构体
 * @return 0:OK 发送成功 -1:ERR 发送失败
 */
int OpenChaoJi_secc_hal_information_send_can_voluation(OpenChaoJi_hal_handle handle, const struct can_pdu * can_send_info)
{
    HAL_DEBUG_LINE

    struct secc_hal_info * info = secc_hal_handle2Info(handle);
    if (info == NULL)
    {
        LOG_ALERT("Invalid hal_handle %08X", handle);
        return -1;
    }

    return hal_send_can_pdu(handle, info->socket_secc, &info->dest_addr_evcc, can_send_info);
}


/******************************控制继电器及反馈******************************/

/**
 * @brief  控制直流接触器
 * @param  OpenChaoJi_hal_handle: 句柄
 * @param  ctl: 0-断开 1-闭合
 * @return void
 * @remark C1\C2
 */
void OpenChaoJi_secc_hal_gbt_close_dc_relay(OpenChaoJi_hal_handle handle,unsigned char ctl)
{
    HAL_DEBUG_LINE

    struct secc_hal_info * info = secc_hal_handle2Info(handle);
    if (info == NULL)
    {
        LOG_ALERT("Invalid hal_handle %08X", handle);
        return;
    }

    hal_x86_relay_set(info->idx, &info->relay_dc, ctl);

    return;
}

/**
 * @brief  控制交流接触器
 * @param  OpenChaoJi_hal_handle: 句柄
 * @param  ctl: 0-断开 1-闭合
 * @return void
 */
void OpenChaoJi_secc_hal_gbt_close_ac_relay(OpenChaoJi_hal_handle handle,unsigned char ctl)
{
    HAL_DEBUG_LINE

    struct secc_hal_info * info = secc_hal_handle2Info(handle);
    if (info == NULL)
    {
        LOG_ALERT("Invalid hal_handle %08X", handle);
        return;
    }

    hal_x86_relay_set(info->idx, &info->relay_ac, ctl);

    return;
}

/**
 * @brief  控制辅助电源供电
 * @param  OpenChaoJi_hal_handle: 句柄
 * @param  ctl: 0-断开 1-闭合
 * @return void
 */
void OpenChaoJi_secc_hal_gbt_a_close_aux_power(OpenChaoJi_hal_handle handle,unsigned char ctl)
{
    HAL_DEBUG_LINE

    struct secc_hal_info * info = secc_hal_handle2Info(handle);
    if (info == NULL)
    {
        LOG_ALERT("Invalid hal_handle %08X", handle);
        return;
    }

    hal_x86_relay_set(info->idx, &info->relay_aux, ctl);

    return;
}

/**
 * @brief  控制电子锁锁止
 * @param  OpenChaoJi_hal_handle: 句柄
 * @param  ctl: 0-断开 1-闭合
 * @return void
 */
void OpenChaoJi_secc_hal_gbt_a_lock(OpenChaoJi_hal_handle handle,unsigned char ctl)
{
    HAL_DEBUG_LINE

    struct secc_hal_info * info = secc_hal_handle2Info(handle);
    if (info == NULL)
    {
        LOG_ALERT("Invalid hal_handle %08X", handle);
        return;
    }

    hal_x86_relay_set(info->idx, &info->relay_lock, ctl);

    return;
}

/**
 * @brief  控制S0
 * @param  OpenChaoJi_hal_handle: 句柄
 * @param  ctl: 0-断开 1-闭合
 * @return void
 */
void OpenChaoJi_secc_hal_gbt_b_close_s0(OpenChaoJi_hal_handle handle, unsigned char ctl)
{
    HAL_DEBUG_LINE

    struct secc_hal_info * info = secc_hal_handle2Info(handle);
    if (info == NULL)
    {
        LOG_ALERT("Invalid hal_handle %08X", handle);
        return;
    }

    hal_x86_relay_set(info->idx, &info->relay_s0, ctl);

    return;
}

/**
 * @brief  控制S1
 * @param  OpenChaoJi_hal_handle: 句柄
 * @param  ctl: 0-断开 1-闭合
 * @return void
 */
void OpenChaoJi_secc_hal_gbt_b_close_s1(OpenChaoJi_hal_handle handle,unsigned char ctl)
{
    HAL_DEBUG_LINE

    struct secc_hal_info * info = secc_hal_handle2Info(handle);
    if (info == NULL)
    {
        LOG_ALERT("Invalid hal_handle %08X", handle);
        return;
    }

    hal_x86_relay_set(info->idx, &info->relay_s1, ctl);

    return;
}

/**
 * @brief  获取直流接触器状态
 * @param  OpenChaoJi_hal_handle: 句柄
 * @return     C1   C2
 *         0   断   断
 *         1   断   通
 *         2   通   断
 *         3   通   通
 * @remark C1\C2
 */
unsigned char OpenChaoJi_secc_hal_get_status_dc_relay(OpenChaoJi_hal_handle handle)
{
    HAL_DEBUG_LINE

    struct secc_hal_info * info = secc_hal_handle2Info(handle);
    if (info == NULL)
    {
        LOG_ALERT("Invalid hal_handle %08X", handle);
        return 0;
    }

    if (hal_x86_relay_get(info->idx, &info->relay_dc) == 1)
    {
        return 3;
    }

    return 0;
}

/**
 * @brief  获取交流接触器状态
 * @param  OpenChaoJi_hal_handle: 句柄
 * @return 0-断开 1-闭合
 */
bool OpenChaoJi_secc_hal_is_close_ac_relay(OpenChaoJi_hal_handle handle)
{
    HAL_DEBUG_LINE

    struct secc_hal_info * info = secc_hal_handle2Info(handle);
    if (info == NULL)
    {
        LOG_ALERT("Invalid hal_handle %08X", handle);
        return 0;
    }

    return hal_x86_relay_get(info->idx, &info->relay_ac);
}

/**
 * @brief  获取辅助电源供电
 * @param  OpenChaoJi_hal_handle: 句柄
 * @return 0-断开 1-闭合
 */
bool OpenChaoJi_secc_hal_gbt_a_is_closed_aux_power(OpenChaoJi_hal_handle handle)
{
    HAL_DEBUG_LINE

    struct secc_hal_info * info = secc_hal_handle2Info(handle);
    if (info == NULL)
    {
        LOG_ALERT("Invalid hal_handle %08X", handle);
        return 0;
    }

    return hal_x86_relay_get(info->idx, &info->relay_aux);
}

/**
 * @brief  获取电子锁锁止
 * @param  OpenChaoJi_hal_handle: 句柄
 * @return 0-断开 1-闭合
 */
bool OpenChaoJi_secc_hal_gbt_a_is_locked(OpenChaoJi_hal_handle handle)
{
    HAL_DEBUG_LINE

    struct secc_hal_info * info = secc_hal_handle2Info(handle);
    if (info == NULL)
    {
        LOG_ALERT("Invalid hal_handle %08X", handle);
        return 0;
    }

    return hal_x86_relay_get(info->idx, &info->relay_lock);
}

/**
 * @brief  获取泄放继电器状态
 * @param  OpenChaoJi_hal_handle: 句柄
 * @return 0-断开 1-闭合
 */
bool OpenChaoJi_secc_hal_gbt_a_is_closed_vent_relay(OpenChaoJi_hal_handle handle)
{
    return 0;
}

/**
 * @brief  获取S0状态
 * @param  OpenChaoJi_hal_handle: 句柄
 * @return 0-断开 1-闭合
 */
bool OpenChaoJi_secc_hal_gbt_b_is_closed_s0(OpenChaoJi_hal_handle handle)
{
    HAL_DEBUG_LINE

    struct secc_hal_info * info = secc_hal_handle2Info(handle);
    if (info == NULL)
    {
        LOG_ALERT("Invalid hal_handle %08X", handle);
        return 0;
    }

    return hal_x86_relay_get(info->idx, &info->relay_s0);
}

/**
 * @brief  获取S1状态
 * @param  OpenChaoJi_hal_handle: 句柄
 * @return 0-断开 1-闭合
 */
bool OpenChaoJi_secc_hal_gbt_b_is_closed_s1(OpenChaoJi_hal_handle handle)
{
    HAL_DEBUG_LINE

    struct secc_hal_info * info = secc_hal_handle2Info(handle);
    if (info == NULL)
    {
        LOG_ALERT("Invalid hal_handle %08X", handle);
        return 0;
    }

    return hal_x86_relay_get(info->idx, &info->relay_s1);
}

/**
 * @brief  获取桩温度
 * @param  OpenChaoJi_hal_handle: 句柄
 * @return 桩温度
 */
int OpenChaoJi_secc_hal_gbt_get_box_temperature(OpenChaoJi_hal_handle handle)
{
    HAL_DEBUG_LINE

    uint32_t ticks = OpenChaoJi_os_get_ticks();

    return (ticks & 0x0F) + 30;
}

/**
 * @brief  获取枪温度
 * @param  OpenChaoJi_hal_handle: 句柄
 * @return 枪温度
 */
struct OpenChaoJi_secc_hal_plug_temp OpenChaoJi_secc_hal_obtain_information_connector_temperature(OpenChaoJi_hal_handle handle)
{
    HAL_DEBUG_LINE
    struct OpenChaoJi_secc_hal_plug_temp temp;

    uint32_t ticks = OpenChaoJi_os_get_ticks();
    temp.plug_n_temp = (ticks & 0x0F) + 30;
    temp.plug_p_temp = temp.plug_n_temp + 1;

    return temp;
}

/**
 * @brief  获取检测点1状态
 * @param  OpenChaoJi_hal_handle: 句柄
 * @return 检测点1状态
 * @remark 返回检测点1的检测电压值
 *
 */
int OpenChaoJi_secc_hal_gbt_get_vol_checkpoint_1(OpenChaoJi_hal_handle handle)
{
    HAL_DEBUG_LINE

    struct secc_hal_info * info = secc_hal_handle2Info(handle);
    if (info == NULL)
    {
        LOG_ALERT("Invalid hal_handle %08X", handle);
        return INVALID_VOLTAGE * 100.0;
    }

    float voltage = hal_pilot_voltage_secc_checkpoint_1(&info->pilot_sync_status);
    return (int)(voltage * 100.0);
}

bool OpenChaoJi_secc_hal_is_emergency_pushed(OpenChaoJi_hal_handle handle)
{
    HAL_DEBUG_LINE

    struct secc_hal_info * info = secc_hal_handle2Info(handle);
    if (info == NULL)
    {
        LOG_ALERT("Invalid hal_handle %08X", handle);
        return 0;
    }

    return hal_x86_relay_get(info->idx, &info->relay_emergency);
}

/******************************获取模块信息******************************/

/**
 * @brief  设置模块输出电流、输出电压
 * @param  OpenChaoJi_hal_handle: 句柄
 * @param  req_volt: 请求电压
 * @param  req_curr: 请求电流
 * @return void
 */
void OpenChaoJi_secc_hal_power_module_request_start(OpenChaoJi_hal_handle handle, unsigned int  req_volt, unsigned int  req_curr)
{
    HAL_DEBUG_LINE

    struct secc_hal_info * info = secc_hal_handle2Info(handle);
    if (info == NULL)
    {
        LOG_ALERT("Invalid hal_handle %08X", handle);
        return;
    }

    secc_hal_power_component_service(info);

    if (req_volt > info->power_component.voltage_max)
    {
        req_volt = info->power_component.voltage_max;
    }
    if (req_volt < info->power_component.voltage_min)
    {
        req_volt = info->power_component.voltage_min;
    }

    if (req_curr > info->power_component.current_max)
    {
        req_curr = info->power_component.current_max;
    }
    if (req_curr < info->power_component.current_min)
    {
        req_curr = info->power_component.current_min;
    }

    bool changed = false;
    if (info->power_component.target_voltage != req_volt)
    {
        info->power_component.target_voltage = req_volt;
        changed = true;
    }
    if (info->power_component.target_current != req_curr)
    {
        info->power_component.target_current = req_curr;
        changed = true;
    }
    if (!info->power_component.start)
    {
        changed = true;
    }

    if (changed)
    {
        info->power_component.start_voltage = info->power_component.voltage;
        info->power_component.start_current = info->power_component.current;
        info->power_component.start_ticks = OpenChaoJi_os_get_ticks();
        info->power_component.start = true;
    }

    return;
}

/**
 * @brief  设置模块关机
 * @param  OpenChaoJi_hal_handle: 句柄
 * @return void
 */
void OpenChaoJi_secc_hal_power_module_request_stop(OpenChaoJi_hal_handle handle)
{
    HAL_DEBUG_LINE

    struct secc_hal_info * info = secc_hal_handle2Info(handle);
    if (info == NULL)
    {
        LOG_ALERT("Invalid hal_handle %08X", handle);
        return;
    }

    secc_hal_power_component_service(info);

    bool changed = false;
    if (info->power_component.target_voltage != 0)
    {
        info->power_component.target_voltage = 0;
        changed = true;
    }
    if (info->power_component.target_current != 0)
    {
        info->power_component.target_current = 0;
        changed = true;
    }
    if (info->power_component.start)
    {
        changed = true;
    }

    if (changed)
    {
        info->power_component.start_voltage = info->power_component.voltage;
        info->power_component.start_current = info->power_component.current;
        info->power_component.start_ticks = OpenChaoJi_os_get_ticks();
        info->power_component.start = false;
    }

    return;
}

/**
 * @brief  获取模块当前开关机状态
 * @param  OpenChaoJi_hal_handle: 句柄
 * @return 开关机状态 0: 关机 1: 开机
 */
bool OpenChaoJi_secc_hal_power_module_is_started(OpenChaoJi_hal_handle handle)
{
    HAL_DEBUG_LINE

    struct secc_hal_info * info = secc_hal_handle2Info(handle);
    if (info == NULL)
    {
        LOG_ALERT("Invalid hal_handle %08X", handle);
        return false;
    }

    return info->power_component.start;
}

/**
 * @brief  获取模块当前输出电压
 * @param  OpenChaoJi_hal_handle: 句柄
 * @return 输出电压
 * @remark 默认返回值为实际数值的10倍、如700V则返回7000
 */
unsigned int OpenChaoJi_secc_hal_power_module_get_voltage(OpenChaoJi_hal_handle handle)
{
    HAL_DEBUG_LINE

    struct secc_hal_info * info = secc_hal_handle2Info(handle);
    if (info == NULL)
    {
        LOG_ALERT("Invalid hal_handle %08X", handle);
        return 0;
    }

    secc_hal_power_component_service(info);

    return info->power_component.voltage;
}

/**
 * @brief  获取模块当前输出电流
 * @param  OpenChaoJi_hal_handle: 句柄
 * @return 输出电流
 * @remark 默认返回值为实际数值的10倍、如100V则返回1000
 */
unsigned int OpenChaoJi_secc_hal_power_module_get_current(OpenChaoJi_hal_handle handle)
{
    HAL_DEBUG_LINE

    struct secc_hal_info * info = secc_hal_handle2Info(handle);
    if (info == NULL)
    {
        LOG_ALERT("Invalid hal_handle %08X", handle);
        return 0;
    }

    secc_hal_power_component_service(info);

    if (info->power_component.current > 4000)
        info->power_component.current = 4000;

    return info->power_component.current;
}

/**
 * @brief  获取模块最大输出电压
 * @param  OpenChaoJi_hal_handle: 句柄
 * @return 最大输出电压
 * @remark 默认返回值为实际数值的10倍、如700V则返回7000
 */
unsigned int OpenChaoJi_secc_hal_power_module_get_max_voltage(OpenChaoJi_hal_handle handle)
{
    HAL_DEBUG_LINE

    struct secc_hal_info * info = secc_hal_handle2Info(handle);
    if (info == NULL)
    {
        LOG_ALERT("Invalid hal_handle %08X", handle);
        return 0;
    }

    return info->power_component.voltage_max;
}

/**
 * @brief  获取最小输出电压
 * @param  OpenChaoJi_hal_handle: 句柄
 * @return 最小输出电压
 * @remark 默认返回值为实际数值的10倍、如700V则返回7000
 */
unsigned int OpenChaoJi_secc_hal_power_module_get_min_voltage(OpenChaoJi_hal_handle handle)
{
    HAL_DEBUG_LINE

    struct secc_hal_info * info = secc_hal_handle2Info(handle);
    if (info == NULL)
    {
        LOG_ALERT("Invalid hal_handle %08X", handle);
        return 0;
    }

    return info->power_component.voltage_min;
}

/**
 * @brief  获取模块最大输出电流
 * @param  OpenChaoJi_hal_handle: 句柄
 * @return 最大输出电流
 * @remark 默认返回值为实际数值的10倍、如100A则返回1000
 */
unsigned int OpenChaoJi_secc_hal_power_module_get_max_current(OpenChaoJi_hal_handle handle)
{
    HAL_DEBUG_LINE

    struct secc_hal_info * info = secc_hal_handle2Info(handle);
    if (info == NULL)
    {
        LOG_ALERT("Invalid hal_handle %08X", handle);
        return 0;
    }

    return info->power_component.current_max;
}

/**
 * @brief  获取最小输出电流
 * @param  OpenChaoJi_hal_handle: 句柄
 * @return 最大输出电流
 * @remark 默认返回值为实际数值的10倍、如100A则返回1000
 */
unsigned int OpenChaoJi_secc_hal_power_module_get_min_current(OpenChaoJi_hal_handle handle)
{
    HAL_DEBUG_LINE

    struct secc_hal_info * info = secc_hal_handle2Info(handle);
    if (info == NULL)
    {
        LOG_ALERT("Invalid hal_handle %08X", handle);
        return 0;
    }

    return info->power_component.current_min;
}
#if 0
/**
 * @brief  获取模块的额定功率
 * @param  OpenChaoJi_hal_handle: 句柄
 * @return 模块的额定功率
 * @remark 默认返回值为 W·H,如20KW则返回20000
 */
unsigned int OpenChaoJi_secc_hal_power_module_get_rated_power(OpenChaoJi_hal_handle handle)
{
    HAL_DEBUG_LINE
    return 0;
}

/**
 * @brief  获取模块告警信息
 * @param  OpenChaoJi_hal_handle: 句柄
 * @return 模块告警信息
 */
unsigned int OpenChaoJi_secc_hal_obtain_information_module_warning(OpenChaoJi_hal_handle handle)
{
    HAL_DEBUG_LINE
    return 0;
}

/**
 * @brief  获取模块故障信息
 * @param  OpenChaoJi_hal_handle: 句柄
 * @return 模块故障信息
 */
unsigned int OpenChaoJi_secc_hal_obtain_information_module_fault(OpenChaoJi_hal_handle handle)
{
    HAL_DEBUG_LINE
    return 0;
}
#endif

/****** 此头文件嘉盛和长园共同维护, 为了避免合并冲突, 嘉盛仅修改本行以上部分, 长园只修改本行以下部分 ******/
// HAL需要自己实现IMD的停止, 并且保留最后的阻值. 同时IMD需要支持多路同时进行, 如果HAL不支持多路, 应用层应当如何处理?
/**
 * @brief  启动阶段-自检启动接口
 * @param  context: 句柄
 * @param  voltage: 绝缘电压值
 * @return  0:OK  -1:ERR
 */
int OpenChaoJi_secc_hal_selfcheck_request_start(OpenChaoJi_hal_handle handle, uint32_t voltage)
{
    HAL_DEBUG_LINE

    struct secc_hal_info * info = secc_hal_handle2Info(handle);
    if (info == NULL)
    {
        LOG_ALERT("Invalid hal_handle %08X", handle);
        return -1;
    }

    info->self_check.start = 1;
    info->self_check.start_ticks = OpenChaoJi_os_get_ticks();

    return 0;
}


/**
 * @brief  启动阶段-自检停止接口
 * @param  context: 句柄
 * @return  0:OK  -1:ERR
 */
int OpenChaoJi_secc_hal_selfcheck_request_stop(OpenChaoJi_hal_handle handle)
{
    HAL_DEBUG_LINE

    struct secc_hal_info * info = secc_hal_handle2Info(handle);
    if (info == NULL)
    {
        LOG_ALERT("Invalid hal_handle %08X", handle);
        return -1;
    }

    info->self_check.start = 0;
    return 0;
}


/**
 * @brief  启动阶段-自检结果获取
 * @param  context: 句柄
 * @param  rp_value: 正对地阻值存储地址
 * @param  rn_value: 负对地阻值存储地址
 * @return  粘连/短路/绝缘 自检状态和结果
 */
struct OpenChaoJi_secc_hal_selfdata  OpenChaoJi_secc_hal_selfcheck_get_result(OpenChaoJi_hal_handle handle)
{
    HAL_DEBUG_LINE

    struct OpenChaoJi_secc_hal_selfdata data = {
        .selfsta_adhesion = SELFSTA_ADHESION_NOTSTART,
        .selfsta_short = SELFSTA_SHORT_NOTSTART,
        .selfsta_imd = SELFSTA_IMD_NOTSTART,

        .selfres_adhesion = SELFRES_ADHESION_ERROR,
        .selfres_short = SELFRES_SHORT_ERROR,
        .selfres_imd = SELFRES_IMD_ERROR,
    };

    struct secc_hal_info * info = secc_hal_handle2Info(handle);
    if (info == NULL)
    {
        LOG_ALERT("Invalid hal_handle %08X", handle);
        return data;
    }

    uint32_t ticks = OpenChaoJi_os_get_ticks();
    if (info->self_check.start == 1)
    {
        if (ticks - info->self_check.start_ticks > info->self_check.time_adhesion)
        {
            data.selfsta_adhesion = SELFSTA_ADHESION_END;
            data.selfres_adhesion = SELFRES_ADHESION_SUCCESS;
        }
        else
        {
            data.selfsta_adhesion = SELFSTA_ADHESION_ING;
        }

        if (ticks - info->self_check.start_ticks > info->self_check.time_short)
        {
            data.selfsta_short = SELFSTA_SHORT_END;
            data.selfres_short = SELFRES_SHORT_SUCCESS;
        }
        else
        {
            data.selfsta_short = SELFSTA_SHORT_ING;
        }

        if (ticks - info->self_check.start_ticks > info->self_check.time_imd)
        {
            data.selfsta_imd = SELFSTA_IMD_END;
            data.selfres_imd = SELFRES_IMD_SUCCESS;
        }
        else
        {
            data.selfsta_imd = SELFSTA_IMD_ING;
        }
    }

    return data;
}

#if 0
/**
 * @brief  充电阶段-绝缘启动接口
 * @param  context: 句柄
 * @param  voltage: 绝缘电压值
 * @return  0:OK  -1:ERR
 */
int OpenChaoJi_secc_hal_imd_request_start(OpenChaoJi_hal_handle handle, uint32_t voltage)
{
    HAL_DEBUG_LINE
    return 0;
}


/**
 * @brief  充电阶段-绝缘停止接口
 * @param  context: 句柄
 * @return  0:OK  -1:ERR
 */
int OpenChaoJi_secc_hal_imd_request_stop(OpenChaoJi_hal_handle handle)
{
    HAL_DEBUG_LINE
    return 0;
}


/**
 * @brief  充电阶段-绝缘结果获取
 * @param  context: 句柄
 * @param  rp_value: 正对地阻值存储地址
 * @param  rn_value: 负对地阻值存储地址
 * @return  -1: ERR   0:OK  1:Checking
 */
int OpenChaoJi_secc_hal_imd_get_result(OpenChaoJi_hal_handle handle,
                                       uint32_t *rp_value, uint32_t *rn_value)
{
    HAL_DEBUG_LINE
    return 0;
}
#endif

/**
 * @brief  泄放启动
 * @param  context: 句柄
 * @return  0:OK  -1:ERR
 */
int OpenChaoJi_secc_hal_vent_request_start(OpenChaoJi_hal_handle handle)
{
    HAL_DEBUG_LINE
    return 0;
}


/**
 * @brief  泄放停止
 * @param  context: 句柄
 * @return  0:OK  -1:ERR
 */
int OpenChaoJi_secc_hal_vent_request_stop(OpenChaoJi_hal_handle handle)
{
    HAL_DEBUG_LINE
    return 0;
}



/**
 * @brief  电压电流采样值获取
 *
 * @param  context: 句柄
 * @param  samp_value: 采样值存储地址
 * @return  0:OK  -1:ERR
 */
int OpenChaoJi_secc_hal_sampling_value(OpenChaoJi_hal_handle handle,
                                       struct OpenChaoJi_secc_hal_samp *samp_value)
{
    HAL_DEBUG_LINE

    struct secc_hal_info * info = secc_hal_handle2Info(handle);
    if (info == NULL)
    {
        LOG_ALERT("Invalid hal_handle %08X", handle);
        return 0;
    }

    secc_hal_power_component_service(info);

    if (samp_value != NULL)
    {
        if (info->pilot_sync_status.evcc_dc)        // 电池投入的情况下, 外侧电压一定等于电池电压
        {
            samp_value->voltage_out = info->pilot_sync_status.evcc_battery_voltage;

            if (info->pilot_sync_status.secc_dc)    // 内侧电压取决于桩的dc继电器是否闭合, 闭合则也是电池电压, 否则就是模块电压
            {
                samp_value->voltage_in = info->pilot_sync_status.evcc_battery_voltage;
            }
            else
            {
                samp_value->voltage_in = info->power_component.voltage;
            }
        }
        else
        {
            // 电池未投入时, 内侧电压肯定等于模块电压
            samp_value->voltage_in = info->power_component.voltage;

            // 外侧电压取决于桩的dc继电器是否闭合, 闭合则也是模块电压, 否则就是0
            if (info->pilot_sync_status.secc_dc)
            {
                samp_value->voltage_out = info->power_component.voltage;
            }
            else
            {
                samp_value->voltage_out = 0;
            }
        }

        samp_value->current = info->power_component.current;
    }

    return 0;
}

